package com.lijin.download;

import org.apache.commons.io.IOUtils;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpRequest;
import org.apache.http.NoHttpResponseException;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicHeader;
import org.apache.http.protocol.HttpContext;
import org.apache.http.ssl.SSLContextBuilder;

import javax.net.ssl.SSLContext;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;

public abstract class HttpClientUtils {

    private static Integer connectTimeout = 60000;

    private static Integer socketTimeout = 60000;

    private static CloseableHttpClient httpClient ;

    static{
        try{
            SSLContext sslContext = SSLContextBuilder.create().useProtocol(SSLConnectionSocketFactory.SSL).loadTrustMaterial((x, y) -> true).build();
            LayeredConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext);
            /**
             * 支持http和https协议
             */
            Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory> create()
                    .register("https", sslsf)
                    .register("http", new PlainConnectionSocketFactory())
                    .build();
            PoolingHttpClientConnectionManager cm =new PoolingHttpClientConnectionManager(socketFactoryRegistry);
            cm.setMaxTotal(200);
            cm.setDefaultMaxPerRoute(200);

            RequestConfig.Builder configBuilder = RequestConfig.custom();
            // 设置连接超时
            configBuilder.setConnectTimeout(connectTimeout);
            // 设置读取超时
            configBuilder.setSocketTimeout(socketTimeout);
            // 设置从连接池获取连接实例的超时
            configBuilder.setConnectionRequestTimeout(50000);
            // 在提交请求之前 测试连接是否可用
            RequestConfig requestConfig = configBuilder.build();


//            HttpRequestRetryHandler handler = new HttpRequestRetryHandler() {
//                @Override
//                public boolean retryRequest(IOException arg0, int retryTimes, HttpContext arg2) {
//                    if (retryTimes > 2) {
//                        return false;
//                    }
//                    //  如果是超时连接则重试
//                    if(arg0 instanceof ConnectTimeoutException){
//                        return true;
//                    }
//
//                    HttpClientContext clientContext = HttpClientContext.adapt(arg2);
//                    HttpRequest request = clientContext.getRequest();
//                    boolean idempotent = !(request instanceof HttpEntityEnclosingRequest);
//                    if (idempotent) {
//                        // 如果请求被认为是幂等的，那么就重试。即重复执行不影响程序其他效果的
//                        return true;
//                    }
//                    return false;
//                }
//            };
            httpClient = HttpClients.custom()
                    .setConnectionManager(cm)
                    .setSSLContext(sslContext)
                    .setSSLHostnameVerifier((x, y) -> true)
                    .setDefaultRequestConfig(requestConfig)
                    .setRetryHandler((HttpRequestRetryHandler)(IOException arg0, int retryTimes, HttpContext arg2) ->{
                        if (retryTimes > 2) {
                            return false;
                        }
                        //  如果是超时连接则重试
                        if(arg0 instanceof ConnectTimeoutException){
                            return true;
                        }

                        HttpClientContext clientContext = HttpClientContext.adapt(arg2);
                        HttpRequest request = clientContext.getRequest();
                        boolean idempotent = !(request instanceof HttpEntityEnclosingRequest);
                        if (idempotent) {
                            // 如果请求被认为是幂等的，那么就重试。即重复执行不影响程序其他效果的
                            return true;
                        }
                        return false;
                    })
                    .build();
        } catch (Exception e){
            throw new RuntimeException("创建连接池对象异常",e);
        }
    }

    //静态的获取方法
    public static CloseableHttpClient newInstance(){
        return httpClient;
    }

    public static ByteArrayOutputStream getRequest(String url){
        HttpGet httpget = new HttpGet(url);
        httpget.setHeader(new BasicHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8"));
        //设置期望服务端返回的编码
        httpget.setHeader(new BasicHeader("Accept", "text/plain;charset=utf-8"));
        CloseableHttpResponse response = null;
        InputStream content = null;
        try {
            response = httpClient.execute(httpget);
            if (response.getStatusLine().getStatusCode () != 200) {
                httpget.abort();
                httpget.releaseConnection();
                throw new RuntimeException("下载m3u8内容文件异常,响应状态异常："+response.getStatusLine().getStatusCode ());
            }
            ByteArrayOutputStream stream = new ByteArrayOutputStream();
            content = response.getEntity().getContent();
            IOUtils.copy(content,stream);
            return stream;
        } catch (Exception e) {
            httpget.abort();
            throw new RuntimeException("下载m3u8内容文件异常："+url,e);
        } finally {
            IOUtils.closeQuietly(content);
            org.apache.http.client.utils.HttpClientUtils.closeQuietly(response);
        }
    }

}
